package com.woniuxy.util;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.entity.po.stationPile.Station;
import com.woniuxy.entity.po.stationPile.StationSchedule;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

public class TimeCalculator {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * 计算充电站下一次调度切换时间
     *
     * @param station 充电站信息
     * @param schedules 所有有效的调度规则
     * @return 下一次开始和结束时间，如果没有有效规则则返回null
     */
    public static NextTimeResult calculateNextTime(Station station, List<StationSchedule> schedules) {
        if (schedules == null || schedules.isEmpty()) {
            return null;
        }

        // 并行计算所有规则的下一次时间
        return schedules.parallelStream()
                .map(schedule -> calculateBySchedule(station, schedule))
                .filter(result -> result != null)
                .min(Comparator.comparing(NextTimeResult::getStart))
                .orElse(null);
    }

    private static NextTimeResult calculateBySchedule(Station station, StationSchedule schedule) {
        switch (schedule.getType()) {
            case DAILY:
                return calculateDaily(schedule);
            case WEEKLY:
                return calculateWeekly(schedule);
            case MONTHLY:
                return calculateMonthly(schedule);
            case CUSTOM:
                return calculateCustom(schedule);
            default:
                return null;
        }
    }

    // 每日规则（示例实现）
    private static NextTimeResult calculateDaily(StationSchedule schedule) {
        LocalDate baseDate = LocalDate.now();
        LocalTime startTime = schedule.getStartTime();
        LocalTime endTime = schedule.getEndTime();

        // 如果当前时间已过今天的结束时间，从明天开始
        if (LocalTime.now().isAfter(endTime)) {
            baseDate = baseDate.plusDays(1);
        }

        LocalDateTime nextStart = LocalDateTime.of(baseDate, startTime);
        LocalDateTime nextEnd = LocalDateTime.of(baseDate, endTime);

        // 处理跨天情况
        if (endTime.isBefore(startTime)) {
            nextEnd = nextEnd.plusDays(1);
        }

        return new NextTimeResult(nextStart, nextEnd);
    }

    // 优化calculateWeekly方法
    private static NextTimeResult calculateWeekly(StationSchedule schedule) {
        List<Integer> weekdays = parseWeekdays(schedule.getScheduleRule());
        if (weekdays.isEmpty()) {
            return null;
        }
        
        LocalDate today = LocalDate.now();
        int currentDayOfWeek = today.getDayOfWeek().getValue();
        
        // 按照与当前日期的距离排序
        List<Integer> sortedWeekdays = weekdays.stream()
                .map(day -> {
                    // 计算每个日期与今天的距离
                    int distance = (day - currentDayOfWeek + 7) % 7;
                    return distance == 0 ? 7 : distance; // 如果是今天，距离设为7
                })
                .sorted()
                .map(distance -> (currentDayOfWeek + distance - 1) % 7 + 1) // 转回周几
                .collect(Collectors.toList());
        
        // 取第一个（最近的）日期
        int nextDay = sortedWeekdays.get(0);
        int daysToAdd = (nextDay - currentDayOfWeek + 7) % 7;
        if (daysToAdd == 0) {
            // 如果是今天，检查时间是否已过
            LocalTime now = LocalTime.now();
            if (now.isAfter(schedule.getEndTime())) {
                daysToAdd = 7; // 如果已过，取下周同一天
            }
        }
        
        LocalDate nextDate = today.plusDays(daysToAdd);
        return buildDateTimeResult(nextDate, schedule);
    }

    private static NextTimeResult calculateMonthly(StationSchedule schedule) {
        List<Integer> daysOfMonth = parseDaysOfMonth(schedule.getScheduleRule());
        LocalDate today = LocalDate.now();
        
        // 检查本月和下月
        for (int monthOffset = 0; monthOffset < 2; monthOffset++) {
            LocalDate targetMonth = today.plusMonths(monthOffset);
            int monthLength = targetMonth.lengthOfMonth();
            
            for (Integer day : daysOfMonth) {
                // 确保日期有效（处理31日在2月等情况）
                int actualDay = Math.min(day, monthLength);
                LocalDate date = targetMonth.withDayOfMonth(actualDay);
                
                // 如果日期在今天或之后，则返回结果
                if (!date.isBefore(today)) {
                    return buildDateTimeResult(date, schedule);
                }
            }
        }
        
        return null;
    }

    private static NextTimeResult calculateCustom(StationSchedule schedule) { /* 自定义规则逻辑 */
        List<LocalDate> dates = parseCustomDates(schedule.getScheduleRule());
        LocalDate today = LocalDate.now();

        return dates.stream()
                .filter(date -> !date.isBefore(today))
                .min(LocalDate::compareTo)
                .map(date -> buildDateTimeResult(date, schedule))
                .orElse(null);
    }

    // 公共构建方法（处理跨天）
    private static NextTimeResult buildDateTimeResult(LocalDate date, StationSchedule schedule) {
        LocalTime startTime = schedule.getStartTime();
        LocalTime endTime = schedule.getEndTime();
        LocalDateTime now = LocalDateTime.now();
        
        // 特殊处理0点到0点的情况（24小时运营）
        if (startTime.equals(LocalTime.MIN) && endTime.equals(LocalTime.MIN)) {
            LocalDateTime start = LocalDateTime.of(date, startTime);
            LocalDateTime end = LocalDateTime.of(date.plusDays(1), endTime);
            
            // 如果当前时间已过今天的周期，移到下一天
            if (now.isAfter(end)) {
                start = start.plusDays(1);
                end = end.plusDays(1);
            }
            
            return new NextTimeResult(start, end);
        }
        
        // 判断是否跨天
        boolean isOvernight = endTime.isBefore(startTime);
        
        // 构建基础时间范围
        LocalDateTime start = LocalDateTime.of(date, startTime);
        LocalDateTime end = LocalDateTime.of(date, endTime);
        
        // 处理跨天情况
        if (isOvernight) {
            end = end.plusDays(1);
        }
        
        // 如果时间范围已过，移至下一个周期
        if (now.isAfter(end)) {
            start = start.plusDays(1);
            end = end.plusDays(1);
        }
        
        return new NextTimeResult(start, end);
    }

    // JSON解析工具方法
    private static List<Integer> parseWeekdays(String scheduleRule) {
        try {
            JsonNode root = OBJECT_MAPPER.readTree(scheduleRule);
            JsonNode weekdaysNode = root.get("weekdays");
            
            // 增加空值检查
            if (weekdaysNode == null || !weekdaysNode.isArray()) {
                return Collections.emptyList(); // 返回空列表而不是抛出异常
            }
            
            return StreamSupport.stream(weekdaysNode.spliterator(), false)
                    .map(JsonNode::asInt)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            // 记录异常并返回空列表
            System.err.println("周规则解析失败: " + scheduleRule + ", 错误: " + e.getMessage());
            return Collections.emptyList();
        }
    }

    private static List<Integer> parseDaysOfMonth(String scheduleRule) {
        // 解析示例：{"days_of_month": [5,15]}
        try {
            JsonNode root = OBJECT_MAPPER.readTree(scheduleRule);
            return StreamSupport.stream(root.get("days_of_month").spliterator(), false)
                    .map(JsonNode::asInt)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            throw new IllegalArgumentException("月规则解析失败");
        }
    }

    private static List<LocalDate> parseCustomDates(String scheduleRule) {
        // 解析示例：{"dates": ["2025-04-02","2025-04-05"]}
        try {
            JsonNode root = OBJECT_MAPPER.readTree(scheduleRule);
            return StreamSupport.stream(root.get("dates").spliterator(), false)
                    .map(node -> LocalDate.parse(node.asText()))
                    .collect(Collectors.toList());
        } catch (Exception e) {
            throw new IllegalArgumentException("自定义规则解析失败");
        }
    }

    // 时间结果包装类
    @AllArgsConstructor
    @Getter
    public static class NextTimeResult {
        private LocalDateTime start;
        private LocalDateTime end;
    }

}